﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml;
using System.Xml.Linq;

namespace DBXml.Core
{
    public class Store
    {
        public static string location = Constants.PathXml + Constants.FileXml;
        public static string locationIndice = Constants.PathXml + Constants.FileXmlIndice;

        /// <summary>Responsável por verificar se existe o arquivo de "Dado" caso não chama a função "CreateXml(string) (DBXml.Core.Store)" passando a localização para criar o arquivo.</summary>
        public static void Create()
        {
            if (!Directory.Exists(Constants.PathXml))
            {
                Directory.CreateDirectory(Constants.PathXml);
            }
            if (!File.Exists(location))
            {
                CreateXml(location);
            }
        }

        /// <summary>Responsável por criar o índice baseado "DBXml.Core.Store.location" abstraindo seu "id", "nome", "numero".</summary>
        public static void CreateIndice()
        {
            if (File.Exists(location))
            {
                if (!File.Exists(locationIndice))
                {
                    CreateXml(locationIndice);
                }
                XElement xml = XElement.Load(location);
                var items = (from dado in xml.Elements("Dado") select dado).ToArray();
                XElement xmlIndice = XElement.Load(locationIndice);
                xmlIndice.RemoveAll();
                foreach (var dado in items)
                {
                    XElement newIndice = new XElement("Dado");
                    newIndice.Add(new XAttribute("id", dado.Attribute("id").Value));
                    newIndice.Add(new XAttribute("nome", dado.Attribute("nome").Value));
                    newIndice.Add(new XAttribute("numero", dado.Attribute("numero").Value));
                    xmlIndice.Add(newIndice);
                }
                xmlIndice.Save(locationIndice);
            }
        }

        public static void CreateXml(string location)
        {
            XmlTextWriter xml = new XmlTextWriter(location, null);
            xml.WriteStartDocument();
            xml.WriteStartElement("Dados");
            xml.WriteEndElement();
            xml.WriteEndDocument();
            xml.Close();
        }

        /// <summary>Responsável por adicionar ou atualizar um "Dado" quando o "Id" for "0" é adicionado um novo "Dado" caso tenha valor o "Dado" correspondente é atualizado.</summary>
        /// <param name="content">Todos os campos a serem adicionados ou atualizados.</param>
        public static void Add(XElement content)
        {
            XElement xml = XElement.Load(location);
            int idDado = Convert.ToInt32(content.Attribute("id").Value);
            if (idDado == 0)
            {
                int id = Convert.ToInt32(xml.Elements().Max(idEle => idEle.Attribute("id").Value)) + 1;
                content.Attribute("id").SetValue(id);
                xml.Add(content);
            }
            else
            {
                var items = (from dado in xml.Elements("Dado") select dado).ToArray();
                xml.RemoveAll();
                foreach (var dado in items)
                {
                    if (Convert.ToInt32(dado.Attribute("id").Value) == idDado)
                    {
                        dado.Attribute("nome").SetValue(content.Attribute("nome").Value);
                        dado.Attribute("sexo").SetValue(content.Attribute("sexo").Value);
                        dado.Attribute("numero").SetValue(content.Attribute("numero").Value);
                        dado.Attribute("telefone").SetValue(content.Attribute("telefone").Value);
                        dado.Attribute("endereco").SetValue(content.Attribute("endereco").Value);
                        dado.Attribute("cidade").SetValue(content.Attribute("cidade").Value);
                        dado.Attribute("estado").SetValue(content.Attribute("estado").Value);
                    }
                    xml.Add(dado);
                }
            }
            xml.Save(location);
        }

        /// <summary> Faz ordenação do índece do acordo com o "Constants.TipoOrdenacao"</summary>
        /// <param name="tipoOrdenacao">Se vai ordenar por "Nome ou Numero"</param>
        public static void Search(Constants.TipoOrdenacao tipoOrdenacao)
        {
            string file = locationIndice;
            XElement xml = XElement.Load(file);
            var items = (from dado in xml.Elements("Dado") select dado).ToArray();
            Sort<XElement> mySort = new Sort<XElement>();
            XElement[] actual = mySort.SelectionSort(items, 0, items.Length, new AlphanumComparatorFast(tipoOrdenacao).Compare);
            xml.RemoveAll();
            foreach (var dado in items) xml.Add(dado);
            xml.Save(file);
        }

        /// <summary> Faz filtro dos "Dado" que está no índice e chama "Search(DBXml.Constants.TipoOrdenacao) (DBXml.Core.Store)" para fazer a ordenação.</summary>
        /// <param name="tipoOrdenacao">Se vai ordenar por "Nome ou Numero"</param>
        /// <param name="nome">Corresponde ao "Nome" usado para filtrar</param>
        /// <param name="numero">Corresponde ao "Número do cliente" usado para filtrar</param>
        public static void Search(Constants.TipoOrdenacao tipoOrdenacao, string nome, decimal numero)
        {
            string file = locationIndice;
            XElement xml = XElement.Load(file);
            var items = (from dado in xml.Elements("Dado") select dado).ToArray();

            Search pesquisar = new Search();
            if (nome.Trim() != "" && numero == 0)
            {
                items = pesquisar.Sequencial(nome.Trim(), items);
                if (items != null)
                {
                    xml.RemoveAll();
                    foreach (var dado in items) xml.Add(dado);
                    xml.Save(file);
                }
                else
                {
                    System.Windows.Forms.MessageBox.Show("Nome não encontrado.");
                }
            }
            else if (nome.Trim() == "" && numero != 0)
            {
                //var items = (from dado in xml.Elements("Dado") where Convert.ToInt32(dado.Attribute("numero").Value) == numero select dado).ToArray();
                int posicao = pesquisar.Binaria(numero, items);
                xml.RemoveAll();
                if (posicao != -1)
                {
                    xml.Add(Store.RecuperarDado(posicao));
                    xml.Save(file);
                }
                else
                {
                    System.Windows.Forms.MessageBox.Show("Número não encontrado.");
                }
            }
            Search(tipoOrdenacao);
        }

        /// <summary>Retorna todos os dados correspondente ao item do "Id" passado como parametro.</summary>
        /// <param name="id">"Id" correspondente ao "Dado".</param>
        /// <returns>item "Dado" do "Id"</returns>
        public static XElement RecuperarDado(int id)
        {
            XElement xml = XElement.Load(location);
            var item = (from dado in xml.Elements("Dado") where Convert.ToInt32(dado.Attribute("id").Value) == id select dado).FirstOrDefault();
            return item;
        }

        public static XElement RecuperarIndice(int id)
        {
            XElement xml = XElement.Load(locationIndice);
            var item = (from dado in xml.Elements("Dado") where Convert.ToInt32(dado.Attribute("id").Value) == id select dado).FirstOrDefault();
            return item;
        }

        /// <summary> Delete o "Dado" correspondente ao "Id" passado como parametro.</summary>
        /// <param name="id">"Id" correspondente ao "Dado".</param>
        public static void Deletar(int id)
        {
            XElement xml = XElement.Load(location);
            var items = (from dado in xml.Elements("Dado") select dado).ToArray();
            xml.RemoveAll();
            foreach (var dado in items)
            {
                if (Convert.ToInt32(dado.Attribute("id").Value) != id)
                {
                    xml.Add(dado);
                }
            }
            xml.Save(location);
        }
    }
}